home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / iproute.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-30  |  22.1 KB  |  837 lines

  1. /* Lower half of IP, consisting of gateway routines
  2.  * Includes routing and options processing code
  3.  *
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  *
  6.  * Mods by PA0GRI
  7.  */
  8. #include "global.h"
  9. #include "config.h"
  10. #include "mbuf.h"
  11. #include "iface.h"
  12. #include "timer.h"
  13. #include "internet.h"
  14. #include "ip.h"
  15. #include "netuser.h"
  16. #include "icmp.h"
  17. #include "rip.h"
  18. #include "trace.h"
  19. #include "pktdrvr.h"
  20. #include "bootp.h"
  21.  
  22.  
  23. struct route *Routes[32][HASHMOD];    /* Routing table */
  24. struct route R_default = {        /* Default route entry */
  25.     NULLROUTE, NULLROUTE,
  26.     0,0,0,
  27.     RIP_INFINITY        /* Init metric to infinity */
  28. };
  29.  
  30. static struct rt_cache Rt_cache;
  31.  
  32. #ifdef IPACCESS
  33. struct rtaccess *IPaccess = NULLACCESS; /* access list */
  34. #endif
  35.  
  36. /* Initialize modulo lookup table used by hash_ip() in pcgen.asm */
  37. void
  38. ipinit()
  39. {
  40.     int i;
  41.  
  42.     for(i=0;i<256;i++)
  43.         Hashtab[i] = i % HASHMOD;
  44. }
  45.  
  46. /* Route an IP datagram. This is the "hopper" through which all IP datagrams,
  47.  * coming or going, must pass.
  48.  *
  49.  * "rxbroadcast" is set to indicate that the packet came in on a subnet
  50.  * broadcast. The router will kick the packet upstairs regardless of the
  51.  * IP destination address.
  52.  */
  53.  
  54. int
  55. ip_route(i_iface,bp,rxbroadcast)
  56. struct iface *i_iface;    /* Input interface */
  57. struct mbuf *bp;    /* Input packet */
  58. int rxbroadcast;    /* True if packet had link broadcast address */
  59. {
  60.     struct ip ip;            /* IP header being processed */
  61.     int16 ip_len;            /* IP header length */
  62.     int16 length;            /* Length of data portion */
  63.     int32 gateway;            /* Gateway IP address */
  64.     register struct route *rp;    /* Route table entry */
  65.     struct iface *iface;        /* Output interface, possibly forwarded */
  66.     int16 offset;            /* Offset into current fragment */
  67.     int16 mf_flag;            /* Original datagram MF flag */
  68.     int strict = 0;            /* Strict source routing flag */
  69.     char prec;            /* Extracted from tos field */
  70.     char del;
  71.     char tput;
  72.     char rel;
  73.     int16 opt_len;        /* Length of current option */
  74.     char *opt;        /* -> beginning of current option */
  75.     int i;
  76.     struct mbuf *tbp;
  77.     int ckgood = IP_CS_OLD; /* Has good checksum without modification */
  78. #ifdef IPACCESS
  79.     int16 srcport, dstport;    /* for use in access checking */
  80.     struct rtaccess *tpacc;    /* temporary for access checking */
  81. #endif
  82.     int pointer;        /* Relative pointer index for sroute/rroute */
  83.  
  84.     if(i_iface != NULLIF){
  85.         ipInReceives++;    /* Not locally generated */
  86.         i_iface->iprecvcnt++;
  87.     }
  88.     if(len_p(bp) < IPLEN){
  89.         /* The packet is shorter than a legal IP header */
  90.         ipInHdrErrors++;
  91.         free_p(bp);
  92.         return -1;
  93.     }
  94.     /* Sneak a peek at the IP header's IHL field to find its length */
  95.     ip_len = (bp->data[0] & 0xf) << 2;
  96.     if(ip_len < IPLEN){
  97.         /* The IP header length field is too small */
  98.         ipInHdrErrors++;
  99.         free_p(bp);
  100.         return -1;
  101.     }
  102.     if(cksum(NULLHEADER,bp,ip_len) != 0){
  103.         /* Bad IP header checksum; discard */
  104.         ipInHdrErrors++;
  105.         free_p(bp);
  106.         return -1;
  107.     }
  108.     /* Extract IP header */
  109.     ntohip(&ip,&bp);
  110.  
  111.     if(ip.version != IPVERSION){
  112.         /* We can't handle this version of IP */
  113.         ipInHdrErrors++;
  114.         free_p(bp);
  115.         return -1;
  116.     }
  117.  
  118.     /* IP logging added - WG7J
  119.      * only if not an AX.25 interface, since those are already
  120.      * logged in ax_recv() in ax25.c
  121.      */
  122.     if((i_iface != NULLIF) && (i_iface->type != CL_AX25) &&
  123.        (i_iface->flags & LOG_IPHEARD) )
  124.         log_ipheard(ip.source,i_iface);
  125.  
  126.     /* Trim data segment if necessary. */
  127.     length = ip.length - ip_len;    /* Length of data portion */
  128.     trim_mbuf(&bp,length);    
  129.                 
  130.     /* If we're running low on memory, return a source quench */
  131.     if(!rxbroadcast && availmem() < Memthresh)
  132.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULLICMP);
  133.  
  134.     /* Process options, if any. Also compute length of secondary IP
  135.      * header in case fragmentation is needed later
  136.      */
  137.     strict = 0;
  138.     for(i=0;i<ip.optlen;i += opt_len){
  139.  
  140.         /* First check for the two special 1-byte options */
  141.         switch(ip.options[i] & OPT_NUMBER){
  142.         case IP_EOL:
  143.             goto no_opt;    /* End of options list, we're done */
  144.         case IP_NOOP:
  145.             opt_len = 1;
  146.             continue;    /* No operation, skip to next option */
  147.         }
  148.         /* Not a 1-byte option, so ensure that there's at least
  149.          * two bytes of option left, that the option length is
  150.          * at least two, and that there's enough space left for
  151.          * the specified option length.
  152.          */
  153.         if(ip.optlen - i < 2
  154.          || ((opt_len = uchar(ip.options[i+1])) < 2)
  155.          || ip.optlen - i < opt_len){
  156.             /* Truncated option, send ICMP and drop packet */
  157.             if(!rxbroadcast){
  158.                 union icmp_args icmp_args;
  159.  
  160.                 icmp_args.pointer = IPLEN + i;
  161.                 icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  162.             }
  163.             free_p(bp);
  164.             return -1;
  165.         }
  166.         opt = &ip.options[i];
  167.  
  168.         switch(opt[0] & OPT_NUMBER){
  169.         case IP_SSROUTE:    /* Strict source route & record route */
  170.             strict = 1;    /* note fall-thru */
  171.         case IP_LSROUTE:    /* Loose source route & record route */
  172.             /* Source routes are ignored unless we're in the
  173.              * destination field
  174.              */
  175.             if(opt_len < 3){
  176.                 /* Option is too short to be a legal sroute.
  177.                  * Send an ICMP message and drop it.
  178.                  */
  179.                 if(!rxbroadcast){
  180.                     union icmp_args icmp_args;
  181.  
  182.                     icmp_args.pointer = IPLEN + i;
  183.                     icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  184.                 }
  185.                 free_p(bp);
  186.                 return -1;
  187.             }
  188.             if(ismyaddr(ip.dest) == NULLIF)
  189.                 break;    /* Skip to next option */
  190.             pointer = uchar(opt[2]);
  191.             if(pointer + 4 > opt_len)
  192.                 break;    /* Route exhausted; it's for us */
  193.  
  194.             /* Put address for next hop into destination field,
  195.              * put our address into the route field, and bump
  196.              * the pointer. We've already ensured enough space.
  197.              */
  198.             ip.dest = get32(&opt[pointer]);
  199.             put32(&opt[pointer],locaddr(ip.dest));
  200.             opt[2] += 4;
  201.             ckgood = IP_CS_NEW;
  202.             break;
  203.         case IP_RROUTE:    /* Record route */
  204.             if(opt_len < 3){
  205.                 /* Option is too short to be a legal rroute.
  206.                  * Send an ICMP message and drop it.
  207.                  */
  208.                 if(!rxbroadcast){
  209.                     union icmp_args icmp_args;
  210.  
  211.                     icmp_args.pointer = IPLEN + i;
  212.                     icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  213.                 }
  214.                 free_p(bp);
  215.                 return -1;
  216.             }                
  217.             pointer = uchar(opt[2]);
  218.             if(pointer + 4 > opt_len){
  219.                 /* Route area exhausted; send an ICMP msg */
  220.                 if(!rxbroadcast){
  221.                     union icmp_args icmp_args;
  222.  
  223.                     icmp_args.pointer = IPLEN + i;
  224.                     icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  225.                 }
  226.                 /* Also drop if odd-sized */
  227.                 if(pointer != opt_len){
  228.                     free_p(bp);
  229.                     return -1;
  230.                 }
  231.             } else {
  232.                 /* Add our address to the route.
  233.                  * We've already ensured there's enough space.
  234.                  */
  235.                 put32(&opt[pointer],locaddr(ip.dest));
  236.                  opt[2] += 4;
  237.                 ckgood = IP_CS_NEW;
  238.             }
  239.             break;
  240.         }
  241.     }
  242. no_opt:
  243.  
  244.     /* See if it's a broadcast or addressed to us, and kick it upstairs */
  245.     if(ismyaddr(ip.dest) != NULLIF || rxbroadcast ||
  246.         (WantBootp && bootp_validPacket(&ip, &bp))){
  247. #ifdef    GWONLY
  248.     /* We're only a gateway, we have no host level protocols */
  249.         if(!rxbroadcast)
  250.             icmp_output(&ip,bp,ICMP_DEST_UNREACH,
  251.              ICMP_PROT_UNREACH,NULLICMP);
  252.         ipInUnknownProtos++;
  253.         free_p(bp);
  254. #else
  255.         ip_recv(i_iface,&ip,bp,rxbroadcast);
  256. #endif
  257.         return 0;
  258.     }
  259.     /* Packet is not destined to us. If it originated elsewhere, count
  260.      * it as a forwarded datagram.
  261.      */
  262.     if(i_iface != NULLIF)
  263.         ipForwDatagrams++;
  264.  
  265.     /* Adjust the header checksum to allow for the modified TTL */        
  266.     ip.checksum += 0x100;
  267.     if((ip.checksum & 0xff00) == 0)
  268.         ip.checksum++;    /* end-around carry */
  269.  
  270.     /* Decrement TTL and discard if zero. We don't have to check
  271.      * rxbroadcast here because it's already been checked
  272.      */
  273.     if(--ip.ttl == 0){
  274.         /* Send ICMP "Time Exceeded" message */
  275.         icmp_output(&ip,bp,ICMP_TIME_EXCEED,0,NULLICMP);
  276.         ipInHdrErrors++;
  277.         free_p(bp);
  278.         return -1;
  279.     }
  280.     /* Look up target address in routing table */
  281.     if((rp = rt_lookup(ip.dest)) == NULLROUTE){
  282.         /* No route exists, return unreachable message (we already
  283.          * know this can't be a broadcast)
  284.          */
  285.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  286.         free_p(bp);
  287.         ipOutNoRoutes++;
  288.         return -1;
  289.     }
  290.     rp->uses++;
  291.  
  292.     /* Check for output forwarding and divert if necessary */
  293.     iface = rp->iface;
  294.     if(iface->forw != NULLIF)
  295.         iface = iface->forw;
  296.  
  297. #ifdef IPACCESS
  298. /* At this point we've decided to send the packet out 'iface' (unless it
  299. won't fragment).  Check ip.protocol for tcp or udp.
  300. Should probably have counter on number of dropped packets.
  301. */
  302.     if((ip.protocol == TCP_PTCL) || (ip.protocol==UDP_PTCL)) {
  303.         /* pull up source & destination port */
  304.         srcport = get16(&(bp->data[0])); /*done for futures & debug*/
  305.         dstport = get16(&(bp->data[2]));
  306.     }
  307.     /* for backwards compatibility, if there are *no* entries */
  308.     /* we ignore access control, so everything is legal. Any  */
  309.     /* entry for an iface means default is to drop if no      */
  310.     /* permission found  */
  311.     for( tpacc = IPaccess;tpacc != NULLACCESS;tpacc=tpacc->nxtiface) {
  312.         /*find a matching iface*/
  313.         if(tpacc->iface == iface ){ /* Needs to be authorized */
  314.             if(!ip_check(tpacc, ip.protocol, ip.source, ip.dest, dstport))
  315.                 break;
  316.             /* not found, throw it away. */
  317.             /* if NO access, then drop & increment counter */
  318.             /* see new(er) RFC for proper ICMP codes */
  319.             /* maybe counter is in MIB? else create.*/
  320.             icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  321.             ipOutNoRoutes++;
  322.             free_p(bp);
  323.             return -1;
  324.         }
  325.     }
  326. #endif
  327.     /* Find gateway; zero gateway in routing table means "send direct" */
  328.     if(rp->gateway == 0)
  329.         gateway = ip.dest;
  330.     else
  331.         gateway = rp->gateway;
  332.  
  333.     if(strict && gateway != ip.dest){
  334.         /* Strict source routing requires a direct entry
  335.          * Again, we know this isn't a broadcast
  336.          */
  337.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_ROUTE_FAIL,NULLICMP);
  338.         free_p(bp);
  339.         ipOutNoRoutes++;
  340.         return -1;
  341.     }
  342.     prec = PREC(ip.tos);
  343.     del = ip.tos & DELAY;
  344.     tput = ip.tos & THRUPUT;
  345.     rel = ip.tos & RELIABILITY;
  346.  
  347.     if(ip.length <= iface->mtu){
  348.         /* Datagram smaller than interface MTU; put header
  349.          * back on and send normally.
  350.          */
  351.         if((tbp = htonip(&ip,bp,ckgood)) == NULLBUF){
  352.             free_p(bp);
  353.             return -1;
  354.         }
  355.         iface->ipsndcnt++;
  356.         return (*iface->send)(tbp,iface,gateway,prec,del,tput,rel);
  357.     }
  358.     /* Fragmentation needed */
  359.     if(ip.flags.df){
  360.         /* Don't Fragment set; return ICMP message and drop */
  361.         union icmp_args icmp_args;
  362.  
  363.         icmp_args.mtu = iface->mtu;
  364.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,&icmp_args);
  365.         free_p(bp);
  366.         ipFragFails++;
  367.         return -1;
  368.     }
  369.     /* Create fragments */
  370.     offset = ip.offset;
  371.     mf_flag = ip.flags.mf;        /* Save original MF flag */
  372.     while(length != 0){        /* As long as there's data left */
  373.         int16 fragsize;        /* Size of this fragment's data */
  374.         struct mbuf *f_data;    /* Data portion of fragment */
  375.  
  376.         /* After the first fragment, should remove those
  377.          * options that aren't supposed to be copied on fragmentation
  378.          */
  379.         ip.offset = offset;
  380.         if(length + ip_len <= iface->mtu){
  381.             /* Last fragment; send all that remains */
  382.             fragsize = length;
  383.             ip.flags.mf = mf_flag;    /* Pass original MF flag */
  384.         } else {
  385.             /* More to come, so send multiple of 8 bytes */
  386.             fragsize = (iface->mtu - ip_len) & 0xfff8;
  387.             ip.flags.mf = 1;
  388.         }
  389.         ip.length = fragsize + ip_len;
  390.  
  391.         /* Duplicate the fragment */
  392.         dup_p(&f_data,bp,offset,fragsize);
  393.         if(f_data == NULLBUF){
  394.             free_p(bp);
  395.             ipFragFails++;
  396.             return -1;
  397.         }
  398.         /* Put IP header back on, recomputing checksum */
  399.         if((tbp = htonip(&ip,f_data,IP_CS_NEW)) == NULLBUF){
  400.             free_p(f_data);
  401.             free_p(bp);
  402.             ipFragFails++;
  403.             return -1;
  404.         }
  405.         /* and ship it out */
  406.         if((*iface->send)(tbp,iface,gateway,prec,del,tput,rel) == -1){
  407.             ipFragFails++;
  408.             free_p(bp);
  409.             return -1;
  410.         }
  411.         iface->ipsndcnt++;
  412.         ipFragCreates++;
  413.         offset += fragsize;
  414.         length -= fragsize;
  415.     }
  416.     ipFragOKs++;
  417.     free_p(bp);
  418.     return 0;
  419. }
  420.  
  421. #ifdef ENCAP
  422. int
  423. ip_encap(bp,iface,gateway,prec,del,tput,rel)
  424. struct mbuf *bp;
  425. struct iface *iface;
  426. int32 gateway;
  427. int prec;
  428. int del;
  429. int tput;
  430. int rel;
  431. {
  432.     struct ip ip;
  433.  
  434.     dump(iface,IF_TRACE_OUT,CL_NONE,bp);
  435.     iface->rawsndcnt++;
  436.     iface->lastsent = secclock();
  437.  
  438.     if(gateway == 0L){
  439.         /* Gateway must be specified */
  440.         ntohip(&ip,&bp);
  441.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  442.         free_p(bp);
  443.         ipOutNoRoutes++;
  444.         return -1;
  445.     }
  446.     return ip_send(INADDR_ANY,gateway,IP_PTCL,0,0,bp,0,0,0);
  447. }
  448. #endif /*ENCAP*/
  449.  
  450. /* Add an entry to the IP routing table. Returns 0 on success, -1 on failure */
  451. struct route *
  452. rt_add(target,bits,gateway,iface,metric,ttl,private)
  453. int32 target;        /* Target IP address prefix */
  454. unsigned int bits;    /* Size of target address prefix in bits (0-32) */
  455. int32 gateway;        /* Optional gateway to be reached via interface */
  456. struct iface *iface;    /* Interface to which packet is to be routed */
  457. int32 metric;        /* Metric for this route entry */
  458. int32 ttl;        /* Lifetime of this route entry in sec */
  459. char private;        /* Inhibit advertising this entry ? */
  460. {
  461.     struct route *rp,**hp;
  462.     struct route *rptmp;
  463.     int32 gwtmp;
  464.  
  465.     if(iface == NULLIF)
  466.         return NULLROUTE;
  467.  
  468.     if(bits == 32 && ismyaddr(target))
  469.         return NULLROUTE;    /* Don't accept routes to ourselves */
  470.  
  471.     if(bits > 32)
  472.         bits = 32;        /* Bulletproofing */
  473. #ifdef ENCAP
  474.     /* Encapsulated routes must specify gateway, and it can't be
  475.      *  ourselves
  476.      */
  477.     if(iface == &Encap && (gateway == 0 || ismyaddr(gateway)))
  478.         return NULLROUTE;
  479. #endif
  480.  
  481.     Rt_cache.route = NULLROUTE;    /* Flush cache */
  482.  
  483.     /* Mask off don't-care bits of target */
  484.     target &= ~0L << (32-bits);
  485.  
  486.     /* Zero bits refers to the default route */
  487.     if(bits == 0){
  488.         rp = &R_default;
  489.     } else {
  490.         rp = rt_blookup(target,bits);
  491.     }
  492.     if(rp == NULLROUTE){
  493.         /* The target is not already in the table, so create a new
  494.          * entry and put it in.
  495.          */
  496.         rp = (struct route *)callocw(1,sizeof(struct route));
  497.         /* Insert at head of table */
  498.         rp->prev = NULLROUTE;
  499.         hp = &Routes[bits-1][hash_ip(target)];
  500.         rp->next = *hp;
  501.         if(rp->next != NULLROUTE)
  502.             rp->next->prev = rp;
  503.         *hp = rp;
  504.         rp->uses = 0;
  505.     }
  506.     rp->target = target;
  507.     rp->bits = bits;
  508.     rp->gateway = gateway;
  509.     rp->metric = metric;
  510.     rp->iface = iface;
  511.     rp->flags = private ? RTPRIVATE : 0;    /* Should anyone be told of this route? */
  512.     rp->timer.func = rt_timeout;  /* Set the timer field */
  513.     rp->timer.arg = (void *)rp;
  514.     set_timer(&rp->timer,ttl*1000L);
  515.     stop_timer(&rp->timer);
  516.     start_timer(&rp->timer); /* start the timer if appropriate */
  517.  
  518. #ifdef ENCAP
  519.     /* Check to see if this created an encapsulation loop */
  520.     gwtmp = gateway;
  521.     for(;;){
  522.         rptmp = rt_lookup(gwtmp);
  523.         if(rptmp == NULLROUTE)
  524.             break;    /* No route to gateway, so no loop */
  525.         if(rptmp->iface != &Encap)
  526.             break;    /* Non-encap interface, so no loop */
  527.         if(rptmp == rp){
  528.             rt_drop(target,bits);    /* Definite loop */
  529.             return NULLROUTE;
  530.         }
  531.         if(rptmp->gateway != 0)
  532.             gwtmp = rptmp->gateway;
  533.     }
  534. #endif
  535.     return rp;
  536. }
  537.  
  538. /* Remove an entry from the IP routing table. Returns 0 on success, -1
  539.  * if entry was not in table.
  540.  */
  541. int
  542. rt_drop(target,bits)
  543. int32 target;
  544. unsigned int bits;
  545. {
  546.     register struct route *rp;
  547.  
  548.     Rt_cache.route = NULLROUTE;    /* Flush the cache */
  549.  
  550.     if(bits == 0){
  551.         /* Nail the default entry */
  552.         stop_timer(&R_default.timer);
  553.         R_default.iface = NULLIF;
  554.         return 0;
  555.     }
  556.     if(bits > 32)
  557.         bits = 32;
  558.  
  559.     /* Mask off target according to width */
  560.     target &= ~0L << (32-bits);
  561.  
  562.     /* Search appropriate chain for existing entry */
  563.     for(rp = Routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  564.         if(rp->target == target)
  565.             break;
  566.     }
  567.     if(rp == NULLROUTE)
  568.         return -1;    /* Not in table */
  569.  
  570.     stop_timer(&rp->timer);
  571.     if(rp->next != NULLROUTE)
  572.         rp->next->prev = rp->prev;
  573.     if(rp->prev != NULLROUTE)
  574.         rp->prev->next = rp->next;
  575.     else
  576.         Routes[bits-1][hash_ip(target)] = rp->next;
  577.  
  578.     free((char *)rp);
  579.     return 0;
  580. }
  581. #ifdef TNOS_68K
  582.  
  583. /* Compute hash function on IP address */
  584. int16
  585. hash_ip(addr)
  586. register int32 addr;
  587. {
  588.     register int16 ret;
  589.  
  590.     ret = hiword(addr);
  591.     ret ^= loword(addr);
  592.     return (int16)(ret % HASHMOD);
  593. }
  594. #endif
  595. #ifndef    GWONLY
  596. /* Given an IP address, return the MTU of the local interface used to
  597.  * reach that destination. This is used by TCP to avoid local fragmentation
  598.  */
  599. int16
  600. ip_mtu(addr)
  601. int32 addr;
  602. {
  603.     register struct route *rp;
  604.     struct iface *iface;
  605.  
  606.     rp = rt_lookup(addr);
  607.     if(rp == NULLROUTE || rp->iface == NULLIF)
  608.         return 0;
  609.  
  610.     iface = rp->iface;
  611.     if(iface->forw != NULLIF)
  612.         return iface->forw->mtu;
  613.     else
  614.         return iface->mtu;
  615. }
  616. /* Given a destination address, return the IP address of the local
  617.  * interface that will be used to reach it. If there is no route
  618.  * to the destination, pick the first non-loopback address.
  619.  */
  620. int32
  621. locaddr(addr)
  622. int32 addr;
  623. {
  624.     register struct route *rp;
  625.     struct iface *ifp;
  626.  
  627.     if(ismyaddr(addr) != NULLIF)
  628.         return addr;    /* Loopback case */
  629.  
  630.     rp = rt_lookup(addr);
  631.     if(rp != NULLROUTE && rp->iface != NULLIF)
  632.         ifp = rp->iface;
  633.     else {
  634.         /* No route currently exists, so just pick the first real
  635.          * interface and use its address
  636.          */
  637.         for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
  638. #ifdef ENCAP
  639.             if(ifp != &Loopback && ifp != &Encap)
  640. #else
  641.             if(ifp != &Loopback)
  642. #endif
  643.                 break;
  644.         }
  645.     }
  646.     if(ifp == NULLIF || ifp == &Loopback)
  647.         return 0;    /* No dice */
  648.  
  649. #ifdef ENCAP
  650.     if(ifp == &Encap){
  651.         /* Recursive call - we assume that there are no circular
  652.          * encapsulation references in the routing table!!
  653.          * (There is a check at the end of rt_add() that goes to
  654.          * great pains to ensure this.)
  655.          */
  656.         /* Next couple of lines are a point of discussion
  657.          * The ultimate source for encaptulation is the local
  658.          * IP address. Phil looks for the address of the addres
  659.          * to be used, ending up with the wrong one (in my oppinion)
  660.          * If you disagree set encap ip address to what you want.
  661.          */
  662.         if(Encap.addr != 0)
  663.             return Encap.addr;
  664. #ifdef notdef
  665.         return locaddr(rp->gateway);
  666. #else
  667.         return Ip_addr;
  668. #endif
  669.     }
  670. #endif /*ENCAP*/
  671.     if(ifp->forw != NULLIF)
  672.         return ifp->forw->addr;
  673.     else
  674.         return ifp->addr;
  675. }
  676. #endif /*GWONLY*/
  677. /* Look up target in hash table, matching the entry having the largest number
  678.  * of leading bits in common. Return default route if not found;
  679.  * if default route not set, return NULLROUTE
  680.  */
  681. struct route *
  682. rt_lookup(target)
  683. int32 target;
  684. {
  685.     register struct route *rp;
  686.     int bits;
  687.     int32 tsave;
  688.     int32 mask;
  689.  
  690.     /* Examine cache first */
  691.     if(target == Rt_cache.target && Rt_cache.route != NULLROUTE)
  692.         return Rt_cache.route;
  693.  
  694.     tsave = target;
  695.  
  696.     mask = ~0L;    /* All ones */
  697.     for(bits = 31;bits >= 0; bits--){
  698.         target &= mask;
  699.         for(rp = Routes[bits][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  700.             if(rp->target == target){
  701.                 /* Stash in cache and return */
  702.                 Rt_cache.target = tsave;
  703.                 Rt_cache.route = rp;
  704.                 return rp;
  705.             }
  706.         }
  707.         mask <<= 1;
  708.     }
  709.     if(R_default.iface != NULLIF){
  710.         Rt_cache.target = tsave;
  711.         Rt_cache.route = &R_default;
  712.         return &R_default;
  713.     } else
  714.         return NULLROUTE;
  715. }
  716. /* Search routing table for entry with specific width */
  717. struct route *
  718. rt_blookup(target,bits)
  719. int32 target;
  720. unsigned int bits;
  721. {
  722.     register struct route *rp;
  723.  
  724.     if(bits == 0){
  725.         if(R_default.iface != NULLIF)
  726.             return &R_default;
  727.         else
  728.             return NULLROUTE;
  729.     }
  730.     /* Mask off target according to width */
  731.     target &= ~0L << (32-bits);
  732.  
  733.     for(rp = Routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  734.         if(rp->target == target){
  735.             return rp;
  736.         }
  737.     }
  738.     return NULLROUTE;
  739. }
  740. /* Scan the routing table. For each entry, see if there's a less-specific
  741.  * one that points to the same interface and gateway. If so, delete
  742.  * the more specific entry, since it is redundant.
  743.  */
  744. void
  745. rt_merge(trace)
  746. int trace;
  747. {
  748.     int bits,i,j;
  749.     struct route *rp,*rpnext,*rp1;
  750.  
  751.     for(bits=32;bits>0;bits--){
  752.         for(i = 0;i<HASHMOD;i++){
  753.             for(rp = Routes[bits-1][i];rp != NULLROUTE;rp = rpnext){
  754.                 rpnext = rp->next;
  755.                 for(j=bits-1;j >= 0;j--){
  756.                     if((rp1 = rt_blookup(rp->target,j)) != NULLROUTE
  757.                      && rp1->iface == rp->iface
  758.                      && rp1->gateway == rp->gateway){
  759.                         if(trace > 1)
  760.                             printf("merge %s %d\n",
  761.                              inet_ntoa(rp->target),
  762.                              rp->bits);
  763.                         rt_drop(rp->target,rp->bits);
  764.                         break;
  765.                     }
  766.                 }
  767.             }
  768.         }
  769.     }
  770. }
  771. #ifdef IPACCESS
  772. /* check to see if packet is "authorized".  Returns 0 if matching */
  773. /* permit record is found, -1 if not found or deny record found */
  774. int
  775. ip_check(accptr,protocol,src,dest,port)
  776. struct rtaccess *accptr;
  777. int16 protocol,port;
  778. int32 src,dest;
  779. {
  780.     int32 smask,tmask;
  781.  
  782.     for(;accptr != NULLACCESS;accptr = accptr->nxtbits) {
  783.         if ((accptr->protocol == 0) ||
  784.              (accptr->protocol == protocol)) {
  785.             smask = ~0L << (32 - accptr->sbits);
  786.             tmask = ~0L << (32 - accptr->bits);
  787.             if ((accptr->source == (smask & src)) &&
  788.                 (accptr->target == (tmask & dest)) &&
  789.                 ((accptr->lowport == 0) ||
  790.                  ((port >= accptr->lowport) &&
  791.                   (port <= accptr->highport)))) {
  792.                 return (accptr->status);
  793.             }
  794.         }
  795.     }
  796.     return -1; /* fall through to here if not found */
  797. }
  798. /* add an entry to the access control list */
  799. /* not a lot of error checking 8-) */
  800. void
  801. addaccess(protocol,source,sbits,target,tbits,ifp,low,high,permit)
  802. int16 protocol;            /* IP protocol */
  803. int32 source,target;        /* Source & target IP address prefix */
  804. unsigned int sbits,tbits;    /* Size of address prefix in bits (0-32) */
  805. struct iface *ifp;        /* Interface to which packet may be routed */
  806. int16 low;
  807. int16 high;
  808. int16 permit;
  809. {
  810.     struct rtaccess *tpacc; /*temporary*/
  811.     struct rtaccess *holder; /*for the new record*/
  812.  
  813.     holder = (struct rtaccess *)callocw(1,sizeof(struct rtaccess));
  814.     holder->nxtiface = NULLACCESS;
  815.     holder->nxtbits = NULLACCESS;
  816.     holder->protocol = protocol;
  817.     holder->source = source;
  818.     holder->sbits = sbits;
  819.     holder->target = target;
  820.     holder->bits = tbits;
  821.     holder->iface = ifp;
  822.     holder->lowport = low;
  823.     holder->highport = high;
  824.     holder->status = permit;
  825.     for(tpacc = IPaccess;tpacc != NULLACCESS;tpacc = tpacc->nxtiface)
  826.         if(tpacc->iface == ifp) { /* get to end */
  827.             while(tpacc->nxtbits != NULLACCESS)
  828.                 tpacc = tpacc->nxtbits;
  829.             tpacc->nxtbits = holder;
  830.             return;
  831.         }
  832.   /* iface wasn't found, so just add at head of list */
  833.     holder->nxtiface = IPaccess;
  834.     IPaccess = holder;
  835. }
  836. #endif
  837.